#include "EpollPoller.h"
#include "Channel.h"
#include "Logger.h"


#include <cerrno>
#include <unistd.h>
#include <cstring>

// 表示Channel与Epoll的状态
// Channel未添加到Poller中
const int kNew = -1; // 对应Channel的成员m_index = -1 Channel还未添加到Epoll里面
// Channel已添加到Poller中
const int kAdded = 1; // Channel已经添加到Epoll里面
// Channel从Poller中删除
const int kDeleted = 2; // Channel已经被Epoll删除


EpollPoller::EpollPoller(EventLoop *loop) 
    : Poller(loop)
    , m_epollfd(::epoll_create1(EPOLL_CLOEXEC))
    , m_events(kInitEventListSize) // vector<epoll_event>
{
    if (m_epollfd < 0) {
        LOG_FATAL("epoll_create error:%d \n", errno);
    }
}

EpollPoller::~EpollPoller()
{
    ::close(m_epollfd);
}

Timestamp EpollPoller::poll(int timeoutMs, ChannelList *activeChannels)
{
    LOG_INFO("fd total count:%lu \n", m_channelList.size());
    int numEvents = ::epoll_wait(m_epollfd, &*m_events.begin(), static_cast<int>(m_events.size()), timeoutMs);
    int saveErrno = errno;
    Timestamp now(Timestamp::now());

    if (numEvents > 0) {
        LOG_INFO("%d events happend \n", numEvents);
        fillActiveChannels(numEvents, activeChannels);
        // epoll_event数组不够大，进行扩容
        if (numEvents == m_events.size()) {
            m_events.resize(m_events.size() * 2);
        }
    } else if (numEvents == 0) {
        LOG_INFO("timeout...... \n");
    } else {
        if (saveErrno != EINTR) {
            errno = saveErrno;
            LOG_ERROR("EPollPoller::poll() error......");
        }
    }

    return now;
}

// Channel update remove => EventLoop updateChannel removeChannel => Poller updateChannel removeChannel
void EpollPoller::updateChannel(Channel *channel)
{
    // 通过index可以判断Channel的状态
    const int index = channel->getIndex();
    LOG_INFO("fd = %d events = %d index = %d \n", channel->getFd(), channel->getEvents(), index);

    if (index == kNew || index == kDeleted) {
        if (index == kNew) {
            int fd = channel->getFd();
            m_channelList[fd] = channel; // 添加到ChannelMap中
        }

        // 可能是新添加的，也可能是删除之后再添加的            
        channel->setIndex(kAdded);
        update(EPOLL_CTL_ADD, channel);
    } else {
        // Channel已经在EPollPoller上注册过
        int fd = channel->getFd();
        // 对任何事件都不感兴趣
        if (channel->isNoneEvent()) {
            update(EPOLL_CTL_DEL, channel);
            channel->setIndex(kDeleted);
        } else {
            update(EPOLL_CTL_MOD, channel);
        }
    }
}

// Channel update remove => EventLoop updateChannel removeChannel => Poller updateChannel removeChannel
// 删除Channel : 如果已注册，则从ChannelMap和Poller中删除，并设置为未注册状态
// ChannelList  Poller 
//              ChannelMap  <fd, Channel*>                
void EpollPoller::removeChannel(Channel *channel)
{
    int fd = channel->getFd();
    // 从ChannelMap中删除fd
    m_channelList.erase(fd);
    LOG_INFO("fd = %d \n", fd);

    int index = channel->getIndex();
    if (index == kAdded) {
        update(EPOLL_CTL_DEL, channel);
    }
    channel->setIndex(kNew);
}

// 处理epoll_wait返回的活跃的Channel
void EpollPoller::fillActiveChannels(int numEvents, ChannelList *activeChannels) const
{
    for (int i = 0; i < numEvents; ++ i) {
        Channel* channel = static_cast<Channel*>(m_events[i].data.ptr);
        channel->setRevents(m_events[i].events);
        activeChannels->push_back(channel); // EventLoop可以拿到它的Poller给它返回的所有发生事件ChannelList
    }
}

// 更新Channel epoll_ctl add/mod/del
void EpollPoller::update(int operation, Channel *channel)
{
    struct epoll_event event;
    memset(&event, 0, sizeof(event));

    int fd = channel->getFd();
    // TODO: ??????
    // event.data.fd = fd;
    event.events = channel->getEvents();
    event.data.ptr = channel;
    
    if (::epoll_ctl(m_epollfd, operation, fd, &event) < 0) {
        if (operation == EPOLL_CTL_DEL) {
            LOG_ERROR("epoll_ctl del error:%d \n", errno);
        } else {
            LOG_FATAL("epoll_ctl add/mod error:%d \n", errno);
        }
    }
    
}
